// src/main/services/ResourceService.js
import { ResourceRepository, PrismaManager } from '../repositories/ResourceRepository.js'
import fs from 'fs/promises'
import path from 'path'
import { Prisma } from '@prisma/client/extension'

/**
 * 资源服务类
 * 封装资源管理核心业务逻辑
 */
class ResourceService {
  /**
   * 初始化数据库连接
   * @param {Object} config - 数据库配置对象
   * @returns {Promise<{success: boolean, message: string}>}
   */
  async initializeDatabase(config) {
    // 参数校验增强
    if (!config || typeof config !== 'object') {
      throw new Error('数据库配置必须是非空对象')
    }

    const { user, password, host, port = 3306, database } = config

    // 关键参数缺失检查
    if (!user || !host || !database) {
      throw new Error('缺少必要参数: user/host/database')
    }

    try {
      // 构建安全连接URL
      const databaseUrl = `mysql://${user}:${encodeURIComponent(password)}@${host}:${port}/${database}`

      // 单例化连接管理
      PrismaManager.initialize(databaseUrl)

      // 主动连接测试
      await PrismaManager.getInstance().$connect()
      await PrismaManager.getInstance().$queryRaw`SELECT 1`

      return { success: true, message: '数据库连接成功' }
    } catch (error) {
      // 分类错误处理
      if (error instanceof Prisma.PrismaClientInitializationError) {
        throw new Error(`连接配置错误: ${error.message}`)
      } else if (error.code === 'ETIMEDOUT') {
        throw new Error('连接超时，请检查网络或数据库状态')
      }
      throw new Error(`连接失败: ${error.message}`)
    }
  }

  /**
   * 扫描目录并生成资源数据
   * @param {string} scanPath - 扫描根目录
   * @param {string} host - 静态文件服务器URL
   * @returns {Promise<{resources: Array, errors: Array}>}
   */
  async scanDirectoryAndGenerateData(scanPath, host) {
    // 参数验证
    this.#validateScanParams(scanPath, host)

    // 标准化路径并验证目录
    const normalizedScanPath = path.normalize(scanPath)
    await this.#validateDirectory(normalizedScanPath)

    const resources = []
    const errors = []

    // 非递归扫描目录
    await this.#scanWithQueue(normalizedScanPath, host, resources, errors)

    return { resources, errors }
  }

  /**
   * 保存资源数据到数据库
   * @param {Array} resources - 资源数据数组
   * @returns {Promise<{success: boolean, count: number, message: string, errors: Array}>}
   */
  async saveResources(resources) {
    // 验证输入数据
    if (!Array.isArray(resources)) {
      throw new Error('资源数据必须是数组')
    }

    if (resources.length === 0) {
      return {
        success: true,
        count: 0,
        message: '没有可保存的资源数据',
        errors: []
      }
    }

    // 验证资源对象结构
    //this.#validateResourceStructure(resources)

    try {
      // 批量保存资源
      const result = await ResourceRepository.createMany(resources)

      // 统一处理结果格式
      return this.#formatSaveResult(result)
    } catch (error) {
      console.error('保存资源时出错:', error)
      return {
        success: false,
        count: 0,
        message: `保存失败: ${error.message}`,
        errors: [error.message]
      }
    }
  }

  // ================= 私有方法 =================

  /**
   * 验证扫描参数
   * @private
   */
  #validateScanParams(scanPath, host) {
    if (!scanPath || typeof scanPath !== 'string') {
      throw new Error('无效的扫描路径')
    }

    if (!host || typeof host !== 'string') {
      throw new Error('Host URL 是必需的')
    }
  }

  /**
   * 验证目录有效性
   * @private
   */
  async #validateDirectory(dirPath) {
    const stats = await fs.stat(dirPath)
    if (!stats.isDirectory()) {
      throw new Error('提供的路径不是目录')
    }
  }

  /**
   * 非递归目录扫描
   * @private
   */
  async #scanWithQueue(startPath, host, resources, errors) {
    const queue = [startPath]

    while (queue.length > 0) {
      const currentPath = queue.shift()

      try {
        const items = await fs.readdir(currentPath)
        await this.#processDirectoryItems(
          items,
          currentPath,
          startPath,
          host,
          resources,
          errors,
          queue
        )
      } catch (error) {
        errors.push(`扫描目录 ${currentPath} 失败: ${error.message}`)
      }
    }
  }

  /**
   * 处理目录项
   * @private
   */
  async #processDirectoryItems(items, currentPath, rootPath, host, resources, errors, queue) {
    await Promise.allSettled(
      items.map(async (item) => {
        const fullPath = path.join(currentPath, item)

        try {
          const stats = await fs.stat(fullPath)

          if (stats.isFile()) {
            await this.#processFile(fullPath, rootPath, host, resources)
          } else if (stats.isDirectory()) {
            queue.push(fullPath)
          }
        } catch (error) {
          errors.push(`处理 ${fullPath} 失败: ${error.message}`)
        }
      })
    )
  }

  /**
   * 处理单个文件
   * @private
   */
  #processFile(fullPath, rootPath, host, resources) {
    const relativePath = path.relative(rootPath, fullPath)
    const dirName = path.dirname(relativePath)
    const item = path.basename(fullPath)

    const ext = path.extname(item).substring(1).toLowerCase()
    const title = path.basename(item, `.${ext}`) || item
    const normalizedPath = relativePath.replace(/\\/g, '/')
    const catalog = dirName.replace(/\\/g, '/')
    const cleanHost = host.replace(/\/$/, '')

    resources.push({
      title,
      resourceType: ext,
      catalog: catalog,
      relativePath: normalizedPath,
      fullUrl: `${cleanHost}/${normalizedPath}`,
      host: cleanHost
    })
  }

  /**
   * 验证资源结构
   * @private
   */
  #validateResourceStructure(resources) {
    const isValid = resources.every(
      (res) =>
        res.title && res.resourceType && res.catalog && res.relativePath && res.fullUrl && res.host
    )

    if (!isValid) {
      throw new Error('资源数据格式无效，缺少必要字段')
    }
  }

  /**
   * 格式化保存结果
   * @private
   */
  #formatSaveResult(result) {
    const count = result.count || 0
    const errors = result.errors || []
    const hasErrors = errors.length > 0

    let message
    if (count === 0 && hasErrors) {
      message = '保存失败: ' + errors.join('; ')
    } else if (count > 0 && hasErrors) {
      message = `部分保存成功 (${count} 条记录)，但有错误: ` + errors.join('; ')
    } else if (count > 0) {
      message = `成功保存 ${count} 条资源数据!`
    } else {
      message = '没有数据被保存'
    }

    return {
      success: count > 0 && !hasErrors,
      count,
      message,
      errors
    }
  }
}

export { ResourceService }
// 导出服务实例
export default new ResourceService()
